/* Copyright ©, 2022, ECARX (Hubei) Technology Co., Ltd. All rights reserved.
 *
 * NOTICE: This file contains information which is confidential and proprietary to ECARX
 * (Hubei) Technology Co., Ltd. and/or other developers. No license to any intellectual
 * property rights contained within this file is either granted or implied except as may be
 * provided in an agreement with ECARX (Hubei) Technology Co., Ltd.
 *
 * Any unauthorized copying or distribution of content from this file in whole or in part
 * is prohibited.
 */
#include "vhal_core/persist/Profile.h"

#include <sys/stat.h>

#include <cstdio>
#include <fstream>
#include <memory>
#include <string>

namespace ecarx::vhal::core::persist {

#define CREATED_PREFERENCE_IDS_KEY "created_preference_ids"
#define ACTIVE_PREFERENCE_ID "active_preference_id"

static std::string filePath(const char* path, const char* name) {
    std::string filePath(path);
    if (filePath.find_last_not_of('/') == (filePath.size() - 1)) {
        filePath.append("/");
    }
    filePath.append(name);
    return filePath;
}

Preference::Preference(const char *path, int32_t profileId, int32_t preferenceId)
    : Properties(path, std::string("profile_").append(std::to_string(profileId))
    .append("_").append(std::to_string(preferenceId)).c_str()),
    mProfileId(profileId),
    mPreferenceId(preferenceId),
    mPath(path){
}

Preference::~Preference() {}

int32_t Preference::getPreferenceId() const {
    return mPreferenceId;
}

std::unique_ptr<Preference> Preference::cloneTo(int32_t preferenceId) {
    std::string newFile =
            filePath(mPath.c_str(), std::string("profile_").append(std::to_string(mProfileId))
            .append("_").append(std::to_string(preferenceId)).c_str());

    struct stat buffer;
    if ((stat(newFile.c_str(), &buffer) == 0)) {
        if (remove(newFile.c_str()) != 0) {
            ALOGW("%s: delete %s failed", __func__, newFile.c_str());
        }
    }
    save();
    std::ifstream ifs(getFilePath(), std::ifstream::binary);
    std::ofstream ofs(newFile, std::ifstream::binary | std::ifstream::trunc);
    if (!ifs.good()) {
        ALOGE("%s: ProfileID %d copy preference %d to preference %d failed", __func__, mProfileId, mPreferenceId, preferenceId);
    }
    ofs << ifs.rdbuf();
    ifs.close();
    ofs.close();
    return std::make_unique<Preference>(mPath.c_str(), mProfileId, preferenceId);
}

Profile::Profile(const char* path, int32_t profileId)
    : Properties(path, std::string("profile_").append(std::to_string(profileId)).c_str()),
      mProfileId(profileId),
      mPath(path) {
    // 1. 获取所有的偏好
    mCreatedPreferenceIds= getInt32Array(CREATED_PREFERENCE_IDS_KEY, { 1 });
    for (int preference : mCreatedPreferenceIds) {
        mPreferences.insert_or_assign(preference, std::make_unique<Preference>(mPath.c_str(), profileId, preference));
    }
    // 2. 获取当前激活的偏好
    int32_t activePreferenceId = getInt32(ACTIVE_PREFERENCE_ID, 1);
    // 代表没有创建过这个 Preference
    if (!isCreated(activePreferenceId)) {
        mCreatedPreferenceIds.push_back(activePreferenceId);
        mPreferences.insert_or_assign(activePreferenceId,
                                      std::make_unique<Preference>(mPath.c_str(), profileId, activePreferenceId));
    }
    mActivePreference = mPreferences[activePreferenceId].get();
    setInt32Array(CREATED_PREFERENCE_IDS_KEY, mCreatedPreferenceIds);
    setInt32(ACTIVE_PREFERENCE_ID, mActivePreference->getPreferenceId());
}

Profile::~Profile() {}

int32_t Profile::getProfileId() const {
    return mProfileId;
}

Preference* Profile::getCurrentPreference() {
    return mActivePreference;
}

bool Profile::createPreference(int32_t newPreferenceid, int32_t clonePreferenceid) {
    auto iter = mPreferences.find(newPreferenceid);
    if (iter != mPreferences.end() || isCreated(newPreferenceid)) {
        return false;
    }

    auto exitIter = mPreferences.find(clonePreferenceid);
    if (exitIter != mPreferences.end() || isCreated(clonePreferenceid)) {
        Preference* clonePreferce = exitIter->second.get();
        if (clonePreferce == nullptr) {
            return false;
        }

        // 复制一份偏好
        std::unique_ptr<Preference> newPreference = clonePreferce->cloneTo(newPreferenceid);

        // 保存偏好列表
        mCreatedPreferenceIds.push_back(newPreferenceid);
        mPreferences.insert_or_assign(newPreferenceid, std::make_unique<Preference>(mPath.c_str(), mProfileId, newPreferenceid));
        setInt32Array(CREATED_PREFERENCE_IDS_KEY, mCreatedPreferenceIds);
        return true;
    }
    return false;
}

bool Profile::isCreated(int32_t preferenceId) {
    for (auto pid : mCreatedPreferenceIds) {
        if (pid == preferenceId) {
            return true;
        }
    }
    return false;
}

bool Profile::deletePreference(int32_t preferenceId) {
    if (isCreated(preferenceId)) {
        bool fileDelete = false;
        auto itr = mPreferences.find(preferenceId);
        if (itr != mPreferences.end()) {
            fileDelete = itr->second->deleteFile();
            if (mActivePreference != nullptr && preferenceId == mActivePreference->getPreferenceId()) {
                mActivePreference = nullptr;
            }
            mPreferences.erase(itr);
        } else {
            Preference preference(mPath.c_str(), mProfileId, preferenceId);
            fileDelete = preference.deleteFile();
        }
        if (fileDelete) {
            for (auto it = mCreatedPreferenceIds.begin(); it != mCreatedPreferenceIds.end();) {
                if ((*it) == preferenceId) {
                    it = mCreatedPreferenceIds.erase(it);
                } else {
                    it++;
                }
            }
            setInt32Array(CREATED_PREFERENCE_IDS_KEY, mCreatedPreferenceIds);
            save();
        }
        return fileDelete;
    }
    return false;
}

bool Profile::activePreference(int32_t preferenceId) {
    if (preferenceId < 1 || preferenceId > 3) {
        return false;
    }
    if (mActivePreference != nullptr && mActivePreference->getPreferenceId() == preferenceId) {
        return false;
    }
    setInt32(ACTIVE_PREFERENCE_ID, preferenceId);
    bool switchPreference = false;
    auto itr = mPreferences.find(preferenceId);

    // 未在已创建的偏好中获取到对应的偏好
    if (itr == mPreferences.end()) {
        if (!isCreated(preferenceId)) {
            mCreatedPreferenceIds.push_back(preferenceId);
        }
        switchPreference = true;
        itr = mPreferences.insert_or_assign(preferenceId, std::make_unique<Preference>(mPath.c_str(), mProfileId, preferenceId)).first;
    } else {
        if (!isCreated(preferenceId)) {
            mCreatedPreferenceIds.push_back(preferenceId);
        }
        switchPreference = true;
    }
    // 保存之前的偏好
    if (mActivePreference != nullptr) {
        mActivePreference->save();
    }
    mActivePreference = itr->second.get();

    setInt32Array(CREATED_PREFERENCE_IDS_KEY, mCreatedPreferenceIds);
    setInt32(ACTIVE_PREFERENCE_ID, mActivePreference->getPreferenceId());
    save();
    return itr != mPreferences.end();
}

std::unique_ptr<Profile> Profile::cloneTo(int32_t profileId) {
    std::string newFile =
        filePath(mPath.c_str(), std::string("profile_").append(std::to_string(profileId)).c_str());

    struct stat buffer;
    if ((stat(newFile.c_str(), &buffer) == 0)) {
        if (remove(newFile.c_str()) != 0) {
            ALOGW("%s: delete %s failed", __func__, newFile.c_str());
        }
    }
    save();
    std::ifstream ifs(getFilePath(), std::ifstream::binary);
    std::ofstream ofs(newFile, std::ifstream::binary | std::ifstream::trunc);
    if (!ifs.good()) {
        ALOGE("%s: copy profile %d to profile %dfailed", __func__, mProfileId, profileId);
    }
    ofs << ifs.rdbuf();
    ifs.close();
    ofs.close();
    return std::make_unique<Profile>(mPath.c_str(), profileId);
}


ProfileAuxiliary::ProfileAuxiliary(const char* path) : Properties(path, "ProfileAuxiliary") {}
ProfileAuxiliary::~ProfileAuxiliary() {}



}  // namespace ecarx::vhal::core::persist